var utils = require('./utils');
var session = require('./session');
var UploadQueueSize = 10000 // 上传队列最大数量，超过该数量会自动清除已完成/暂停/已取消的任务，暂不开放给用户

var originApiMap = {};
var transferToTaskMethod = function (apiMap, apiName) {
  originApiMap[apiName] = apiMap[apiName];
  // 每次调用 putUploadFile 和 sliceUploadFile 实际执行了一遍 this._addTask 
  apiMap[apiName] = function (params, callback) {
    this._addTask(apiName, params, callback);
  };
};

var initTask = function (ks3) {
  var queue = [];
  var tasks = {};
  var uploadingFileCount = 0;
  var nextUploadIndex = 0;

  // 接口返回简略的任务信息
  var formatTask = function (task) {
    var t = {
      taskId: task.taskId,
      bucket: task.bucket,
      region: task.region,
      key: task.key,
      filePath: task.filePath,
      state: task.state, // checking uploading waiting paused canceled error success
      loaded: task.loaded,
      size: task.size,
      speed: task.speed,
      percent: task.percent,
      statusCode: task.statusCode,
      error: task.error,
    };
    if (task.FilePath) t.FilePath = task.FilePath;
    return t;
  };

  // 任务列表更新事件
  var emitListUpdate = (function () {
    var timer;
    var emit = function () {
      timer = 0;
      ks3.emit('list-update', { list: queue });
    };
    return function () {
      // 如果没有 timer 就创建一个
      // 避免在短时间多次调用 emitListUpdate
      if (!timer) timer = setTimeout(emit);
    };
  })();

  // 清理任务队列中已完成，取消或不活跃的任务
  var clearQueue = function () {
    if (queue.length <= UploadQueueSize) return; // 小于最大限制，无需清理
    for (
        var i = 0;
        i < nextUploadIndex && // 清理当前处理到的任务索引之前的部分
        i < queue.length &&
        queue.length > UploadQueueSize; // 队列长度超过最大限制

    ) {
      var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading';
      if (!queue[i] || !isActive) {
        tasks[queue[i].taskId] && delete tasks[queue[i].taskId]; // 从 tasks map 中删除
        queue.splice(i, 1); // 从 queue 中移除
        nextUploadIndex--; // 下一个索引任务减一
      } else {
        i++;
      }
    }
    emitListUpdate(); // 触发更新
  };

  // 任务调度：从队列中取出下一个待执行的任务，并启动
  var startNextTask = function () {
    // 检查是否允许增加执行进程，是否达到并发限制
    if (uploadingFileCount >= ks3.config.fileParallelLimit) return;
    // 跳过不可执行的任务
    while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++;
    // 检查是否已遍历结束
    if (nextUploadIndex >= queue.length) return;
    // 上传该遍历到的任务
    var task = queue[nextUploadIndex];
    nextUploadIndex++;
    uploadingFileCount++;
    task.state = 'checking';
    !task.params.UploadData && (task.params.UploadData = {});
    var apiParams = utils.extend({}, task.params);
    originApiMap[task.api].call(ks3, apiParams, function (err, data) {
      if (!ks3._isRunningTask(task.taskId)) return;
      if (!data) {
        // 网络错误
        task.statusCode = 0;
      } else {
        data ? task.statusCode = data.statusCode : 500;
      }
      
      if (task.state === 'checking' || task.state === 'uploading') {
        task.state = err ? 'error' : 'success';
        err && (task.error = err);
        uploadingFileCount--;
        emitListUpdate();
        startNextTask();
        task.callback && task.callback(err, data);
        if (task.state === 'success') {
          if (task.params) {
            delete task.params.UploadData;
            delete task.params.file;
            delete task.params;
          }
          delete task.callback;
        }
      }
      clearQueue();
    });
    emitListUpdate();
    // 异步执行下一个任务
    setTimeout(startNextTask);
  };

  var killTask = function (id, switchToState) {
    var task = tasks[id];
    if (!task) return;
    var waiting = task && task.state === 'waiting';
    var running = task && (task.state === 'checking' || task.state === 'uploading'); // 检查中或者上传中视为 running
    if (
        (switchToState === 'canceled' && task.state !== 'canceled') ||
        (switchToState === 'paused' && waiting) ||
        (switchToState === 'paused' && running)
    ) { // 如果是要变成取消或者暂停状态
      if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') {
        console.error('stream not support pause');
        return;
      }
      task.state = switchToState;
      ks3.emit('inner-kill-task', { taskId: id, toState: switchToState });
      try {
        var UploadId = task && task.params && task.params.UploadData.UploadId;
      } catch (e) {}
      if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId); // 如果是取消，从 session 中移除
      emitListUpdate();
      if (running) {
        uploadingFileCount--;
        startNextTask();
      }
      if (switchToState === 'canceled') {
        if (task.params) {
          delete task.params.UploadData;
          delete task.params.file;
          delete task.params;
        }
        delete task.callback;
      }
    }
    clearQueue();
  };

  // 给 ks3 实例增加任务方法
  ks3._addTasks = function (taskList) {
    utils.each(taskList, function (task) {
      ks3._addTask(task.api, task.params, task.callback, true);
    });
    emitListUpdate();
  };
  
  ks3._addTask = function (api, params, callback, ignoreAddEvent) {
    // 复制参数对象
    params = utils.extend({}, params);

    // 生成随机id
    var id = utils.uuid();
    params.taskId = id;
    params.onTaskReady && params.onTaskReady(id);

    var task = {
      params: params,
      callback: callback,
      api: api,
      index: queue.length,
      taskId: id,
      bucket: params.bucket,
      region: params.region,
      key: params.key,
      state: 'waiting', // 状态：等待 
      loaded: 0, // 加载大小
      size: 0,
      speed: 0, // 速度
      percent: 0, // 进度
      error: null,
      statusCode: null
    };
    
    var onProgress = params.onProgress;
    params.onProgress = function (info) {
      if (!ks3._isRunningTask(task.taskId)) return;
      task.state === 'checking' && (task.state = 'uploading'); // 将 checking 状态改为 uploading
      task.loaded = info.loaded;
      task.speed = info.speed;
      task.percent = info.percent;
      onProgress && onProgress(info);
      emitListUpdate();
    };

    // 异步获取 filesize
    utils.getFileSize(api, params, function (err, size) {
      // 开始处理上传
      if (err) return callback(err); // 如果获取大小出错，不加入队列
      // 获取完文件大小再把任务加入队列
      tasks[id] = task;
      queue.push(task);
      task.size = size;

      emitListUpdate()
      startNextTask();
    });
    return id;
  };

  // 是否是正在运行的任务
  ks3._isRunningTask = function (id) {
    var task = tasks[id];
    return !!(task && (task.state === 'checking' || task.state === 'uploading'));
  };

  // 获取任务列表
  ks3.getTaskList = function () {
    return utils.map(queue, formatTask);
  };

  // 取消任务
  ks3.cancelTask = function (id) {
    killTask(id, 'canceled');
  };

  // 暂停任务
  ks3.pauseTask = function (id) {
    killTask(id, 'paused');
  };

  // 重试任务
  ks3.restartTask = function (id) {
    var task = tasks[id];
    if (task && (task.state === 'paused' || task.state === 'error')) {
      task.state = 'waiting';
      emitListUpdate();
      nextUploadIndex = Math.min(nextUploadIndex, task.index);
      startNextTask();
    }
  };

  ks3.isUploadRunning = function () {
    return uploadingFileCount || nextUploadIndex < queue.length;
  };
};

module.exports.transferToTaskMethod = transferToTaskMethod;
module.exports.init = initTask;
